<template>
	<div class="acf-sound">
		<h3>振荡音</h3>
		<div class="acf-sound-list">
			<div 
				v-for="sound in soundStore.oscSounds"
				:key="sound.id"
				class="acf-sound-list-item">
				<UIIcon icon="play" @click="vocalSound(sound.freq, null)" />
				{{sound.name}} - (频率: {{sound.freq}})
				<el-button-group size="small">
					<el-popconfirm title="确定删除" confirm-button-text="确定" cancel-button-text="取消" hide-icon @confirm="deleteSound(sound)">
						<template v-slot:reference>
							<el-button v-show="sound.modify" type="danger" icon="Delete"></el-button>
						</template>
					</el-popconfirm>
				</el-button-group> 
			</div>
			<div class="acf-sound-list-item acf-sound-list-add" @click="oscAddDialogVisible = true">
				<el-icon><CirclePlusFilled /></el-icon>
				添加
			</div>
		</div>
		
		<h3>自选音</h3>
		<div class="acf-sound-list">
			<div
				v-for="sound in soundStore.customSounds"
				:key="sound.id"
				class="acf-sound-list-item">
				<UIIcon icon="play" @click="vocalSound(null, sound.buffer)" />
				{{sound.name}} - (频率: {{sound.freq}})
				<el-button-group size="small">
					<el-popconfirm title="确定删除" confirm-button-text="确定" cancel-button-text="取消" hide-icon @confirm="deleteSound(sound)">
						<template v-slot:reference>
							<el-button v-show="sound.modify" type="danger" icon="Delete"></el-button>
						</template>
					</el-popconfirm>
				</el-button-group> 
			</div>
			<div class="acf-sound-list-item acf-sound-list-add" @click="customAddDialogVisible = true">
				<el-icon><CirclePlusFilled /></el-icon>
				添加
			</div>
		</div>
		
		<el-dialog
			v-model="oscAddDialogVisible"
			title="添加振荡音"
			width="clamp(300px, 67%, 600px)">
			<el-form :model="oscFormModel" ref="oscFormElement" :rules="oscFormRules" label-width="60">
				<el-form-item label="命名" prop="name">
					<el-input v-model="oscFormModel.name" />
					<el-alert title="若不命名,将以频率自动命名" type="info" :closable="false" show-icon style="margin-top: 10px;" />
				</el-form-item>
				<el-form-item label="频率" prop="freq">
					<el-slider v-model="oscFormModel.freq" :step="1" :min="28" :max="4186" show-input />
				</el-form-item>
				<el-form-item>
					<el-button @click="vocalPause ? vocalSound(oscFormModel.freq, null) : stopVocal()">{{vocalPause ? '试听' : '停止'}}</el-button>
				</el-form-item>
			</el-form>
			<template v-slot:footer>
				<el-button type="primary" @click="addOscSound">
					添加
				</el-button>
			</template>
		</el-dialog>
		
		<el-dialog
			v-model="customAddDialogVisible"
			title="添加自选音"
			width="clamp(300px, 67%, 600px)">
			<el-form :model="customFormModel" ref="customFormElement" :rules="customFormRules" label-width="60">
				<el-form-item label="命名" prop="name">
					<el-input v-model="customFormModel.name" />
					<el-alert title="默认为文件名" type="info" :closable="false" show-icon style="margin-top: 10px;" />
				</el-form-item>
				<el-form-item label="文件" prop="freq">
					<el-upload
						ref="customUploadElement"
						drag
						:limit="1"
						:auto-upload="false"
						style="flex: 1;"
						@exceed="coverUploadFile"
						@change="downloadAndDecodeFile"
					>
						<el-icon class="el-icon--upload"><upload-filled /></el-icon>
						<div>点击或者拖拽音频文件</div>
					</el-upload>
				</el-form-item>
				<el-form-item>
					<el-progress :percentage="ddPercentage" style="flex: 1;">
						<el-button @click="vocalPause ? vocalSound(null, customFormModel.buffer) : stopVocal()" :disabled="ddPercentage != 100">{{vocalPause ? '试听' : '停止'}}</el-button>
					</el-progress>
				</el-form-item>
			</el-form>
			<template v-slot:footer>
				<el-button type="primary" @click="addCustomSound">
					添加
				</el-button>
			</template>
		</el-dialog>
	</div>
</template>

<script setup>
	
	import { ref, reactive, watch, computed, onDeactivated } from 'vue';
	import UIIcon from '@/ui/icon';
	import useSoundStore from './useSoundStore';
	import pluginMessage from '@/plugins/message';
	import * as axreq from '@/api/request';
	import * as $audio from './audio';
	
	const soundStore = useSoundStore();
	
	const oscAddDialogVisible = ref(false);
	const oscFormModel = reactive({
		freq: 440,
		name: null
	})
	const oscFormRules = reactive({
		freq: [{
			required: true,
			message: '请输入',
			trigger: 'change'
		}, {
			validator: (rule, value, callback) => {
				if (soundStore.oscSounds.some(sound => sound.freq === value)) {
					callback('已存在此频率振荡音')
				} else {
					callback();
				}
			},
			trigger: 'blur'
		}]
	})
	const oscFormElement = ref();
	
	const customAddDialogVisible = ref(false);
	const customFormModel = reactive({
		name: null,
		buffer: null,
		files: []
	})
	const customFormRules = reactive({
		name: [{
			required: true,
			message: '请命名',
			trigger: 'change'
		}],
		buffer: [{
			required: true,
			message: '请添加音频文件',
			trigger: 'blur'
		}]
	})
	const customFormElement = ref();
	const customUploadElement = ref();
	const ddPercentage = ref(0);
	
	let soundNode;
	const vocalPause = ref(true);
	
	watch(oscAddDialogVisible, () => {
		stopVocal();
	})
	
	watch(customAddDialogVisible, () => {
		stopVocal();
	})
	
	onDeactivated(() => {
		soundStore.clearAllSound();
	})
	
	function vocalSound(freq, buffer) {
		stopVocal();
		vocalPause.value = false;
		if (freq) {
			soundNode = soundStore.vocalOscSound(freq, function() {
				vocalPause.value = true;
			}, true);
		} else {
			soundNode = soundStore.vocalCustomSound(buffer, function() {
				vocalPause.value = true;
			}, true);
		}
	}
	
	function stopVocal() {
		soundNode?.stop();
		vocalPause.value = true;
	}
	
	function deleteSound(sound) {
		if (sound.freq) {
			soundStore.deleteOscSound(sound.id);
		} else {
			soundStore.deleteCustomSound(sound.id);
		}
	}
	
	function addOscSound() {
		oscFormElement.value.validate((valid) => {
			if (valid) {
				soundStore.addOscSound(oscFormModel.name, oscFormModel.freq);
				pluginMessage.success('添加成功');
			}
		})
	}
	
	function addCustomSound() {
		customFormElement.value.validate((valid) => {
			if (valid) {
				soundStore.addCustomSound(customFormModel.name, customFormModel.buffer);
				pluginMessage.success('添加成功');
			}
		})
	}
	
	function coverUploadFile(files) {
		stopVocal();
		customUploadElement.value.clearFiles();
		customUploadElement.value.handleStart(files[0]);
	}
	
	function downloadAndDecodeFile(file) {
		customFormModel.name = file.name;
		ddPercentage.value = 0;
		const url = URL.createObjectURL(file.raw);
		axreq._get_(url, null, {
			baseURL: null,
			responseType: 'arraybuffer',
			onDownloadProgress: function(progressEvent) {
				ddPercentage.value = Math.round(progressEvent.loaded * 100 / progressEvent.total);
			}
		}).then(({ data }) => {
			ddPercentage.value = 100;
			$audio.context.decodeAudioData(data, (buffer) => {
				customFormModel.buffer = buffer;
			})
			URL.revokeObjectURL(url);
		})
	}
	
</script>

<style lang="scss" scoped>
	
	@import '@/theme/material/media.scss';
	
	.acf-sound {
		display: flex;
		flex-direction: column;
		gap: 20px;
	}
	
	.acf-sound-list {
		display: flex;
		gap: 20px 40px;
		flex-wrap: wrap;
	}
	
	.acf-sound-list-item {
		width: calc((100% - 40px) / 2);
		@include mediaMd {
			width: calc((100% - 120px) / 4);
		}
		display: grid;
		grid-template-columns: auto 1fr auto;
		place-items: center stretch;
		gap: 10px;
		border-radius: 4px;
		border: 1px solid rgba(0, 0, 0, 1.0);
		background: rgba(0, 0, 0, .6);
		padding: 12px 20px;
		box-sizing: border-box;
		transition: .25s linear;
		:deep(.ui-icon) {
			cursor: pointer;
		}
		&:hover {
			color: var(--el-color-primary);
			background: rgba(0, 0, 0, .85);
		}
	}
	
	.acf-sound-list-add {
		color: #444444;
		border: 1px solid rgba(255, 255, 255, 1.0);
		background: rgba(255, 255, 255, .67);
		cursor: pointer;
		&:hover {
			background: rgba(255, 255, 255, .88);
		}
	}
	
</style>